#pragma once

class CEvent
{
public:
	CEvent( const char* iName, bool iManualReset = true, bool iInitialState = false ):m_handle(NULL)
	{
		CreateEvent( iManualReset, iInitialState, iName );
	}

	CEvent( bool iManualReset = true, bool iInitialState = false ):m_handle(NULL)
	{
		CreateEvent( iManualReset, iInitialState, NULL );
	}

	void CreateEvent( bool iManualReset, bool iInitialState, const char* iName )
	{
		SECURITY_ATTRIBUTES	SecurityAttributes;
		SECURITY_DESCRIPTOR	SecurityDescriptor;

		// for NT AUTHORITY\LocalSystem interoperability
		InitializeSecurityDescriptor( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
		SecurityDescriptor.Control |= SE_DACL_PRESENT;
		SecurityAttributes.nLength = sizeof(SecurityAttributes);
		SecurityAttributes.bInheritHandle = FALSE;
		SecurityAttributes.lpSecurityDescriptor = &SecurityDescriptor;
		m_handle = ::CreateEventA( &SecurityAttributes, iManualReset, iInitialState, iName );
		if( m_handle == NULL )
			throw CSystemException(AT);
	}

	void OpenEvent( const char* iName, DWORD iDesiredAccess = EVENT_ALL_ACCESS )
	{
		m_handle = ::OpenEvent( iDesiredAccess, FALSE, iName );
		if( m_handle == NULL )
			throw CSystemException(AT);
	}

	void SetEvent()
	{
		if( !::SetEvent( m_handle ) )
			throw CSystemException(AT);
	}

	void ResetEvent()
	{
		if( !::ResetEvent( m_handle ) )
			throw CSystemException(AT);
	}

	void PulseEvent()
	{
		if( !::PulseEvent( m_handle ) )
			throw CSystemException(AT);
	}

	void Set()
	{
		SetEvent();
	}

	void Reset()
	{
		ResetEvent();
	}

	void Pulse()
	{
		PulseEvent();
	}

	bool Signaled( int iTimeout = 0 ) const
	{
		return WaitForSingleObject(iTimeout) == WAIT_OBJECT_0;
	}

	void WaitForSignal() const
	{
		while( WaitForSingleObject( INFINITE ) != WAIT_OBJECT_0 );
	}
	
	operator HANDLE() const
	{
		return m_handle;
	}
private:
	DWORD WaitForSingleObject( DWORD iTimeout = INFINITE, BOOL iAlertable = TRUE ) const
	{
		DWORD Value;
		
		Value = ::WaitForSingleObjectEx( m_handle, iTimeout, iAlertable );
		if( Value == WAIT_FAILED )
			throw CSystemException(AT);
		return Value;
	}
	HANDLE m_handle;

};
